package diadraw.sharing.dropbox
{
	/**
	 * @author Radoslava Leseva, Radoslava.Leseva@diadraw.com
	 * http://diadraw.com
	 * http://ideadrawapp.com
	 * 
	 * */
	
	import com.adobe.crypto.SHA1;
	import com.diadraw.extensions.dropbox.NativeDropboxLinkEvent;
	import com.diadraw.extensions.dropbox.NativeDropboxLogin;
	
	import diadraw.sharing.dropbox.DropboxObject;
	
	import flash.desktop.NativeApplication;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.InvokeEvent;
	import flash.net.URLRequest;
	import flash.net.URLVariables;
	import flash.net.navigateToURL;
	
	import mx.collections.ArrayList;
	
	import org.hamster.dropbox.DropboxClient;
	import org.hamster.dropbox.DropboxConfig;
	import org.hamster.dropbox.DropboxEvent;
	import org.hamster.dropbox.models.DropboxFile;
	
	
	public class DropboxAPIWrapper extends EventDispatcher
	{
		//---------------------------------------------
		// Public interface
		//---------------------------------------------
		public function DropboxAPIWrapper( 
			_appKey 			: String, 
			_appSecret 			: String, 
			_dropboxAccessType  : String = "kDBRootDropbox",
			_target 			: IEventDispatcher = null )
		{
			super( _target );
			
			m_config = new DropboxConfig( _appKey, _appSecret );
			m_dropboxAccessType = _dropboxAccessType;
			
			ensureApiWrapper();
		}
		
		
		public function isLoggedIn() : Boolean
		{
			ensureApiWrapper();
			return (!isEmpty( m_dropboxAPI.config.accessTokenKey ) && ! isEmpty( m_dropboxAPI.config.accessTokenSecret ) );
		}
		
		
		public function logIn( 	
			_accessKey : String = null, 
			_accessSecret : String = null ) : void
		{	
			ensureApiWrapper();
			
			if ( !isEmpty( _accessKey ) && !isEmpty( _accessSecret ) )
			{
				// If the app has already been linked before and stored the accessKey and acessSecret, 
				// just configure with them and go:
				
				m_dropboxAPI.config.accessTokenKey = _accessKey;
				m_dropboxAPI.config.accessTokenSecret = _accessSecret;
				
				signalLoginComplete();
			}
			else
			{
				if ( null == m_loginExt )
				{
					m_loginExt = new NativeDropboxLogin();
				}
				
				m_loginExt.removeEventListener( NativeDropboxLinkEvent.DROPBOX_LINKED, handleDropboxLinked );
				m_loginExt.addEventListener( NativeDropboxLinkEvent.DROPBOX_LINKED, handleDropboxLinked );
				
				m_loginExt.removeEventListener( NativeDropboxLinkEvent.DROPBOX_LINK_CANCELLED, handleDropboxLinkCancelled );
				m_loginExt.addEventListener( NativeDropboxLinkEvent.DROPBOX_LINK_CANCELLED, handleDropboxLinkCancelled );
				
				m_loginExt.linkWithDropbox( m_config.consumerKey, m_config.consumerSecret, m_dropboxAccessType );
			}
		}
		
		
		public function unlinkFromDropbox() : void
		{
			if ( null == m_loginExt )
			{
				m_loginExt = new NativeDropboxLogin();
			}
			
			m_loginExt.removeEventListener( NativeDropboxLinkEvent.DROPBOX_UNLINKED, handleDropboxUnlinked );
			m_loginExt.addEventListener( NativeDropboxLinkEvent.DROPBOX_UNLINKED, handleDropboxUnlinked );
			
			m_loginExt.unlinkFromDropbox();
		}
		
		
		public function requestFolderContents( _callback : Function, _folderName : String = "" ) : void
		{
			ensureApiWrapper();
			
			var handler : Function = function ( _event : DropboxEvent ) : void
			{	
				var folderContents : ArrayList = new ArrayList();		
				
				for each ( var entry : DropboxFile in _event.resultObject.contents )
				{
					if ( entry.isDir )
					{
						var name : String = entry.path;
						var idx : int = name.lastIndexOf( "/" );
						
						if ( 0 <= idx && idx < ( name.length - 1 ) )
						{
							name = name.slice( idx + 1, name.length );
						}
						
						var path : String = entry.path; 
						var leadingSlashIdx : int = path.indexOf( "/" );
						if ( 0 == leadingSlashIdx )
						{
							path = path.slice( 1, path.length );
						}
						
						var folderObj : DropboxObject = new DropboxObject( name, path );
						
						folderContents.addItem( folderObj );
					}
				}
				
				_callback( folderContents );
			}
			
			if ( !m_dropboxAPI.hasEventListener( DropboxEvent.METADATA_RESULT ) )
			{
				m_dropboxAPI.addEventListener( DropboxEvent.METADATA_RESULT, handler );
			}
			
			var faultHandler : Function = function ( _event : DropboxEvent ) : void
			{				
				m_dropboxAPI.removeEventListener( DropboxEvent.METADATA_FAULT, faultHandler );
				
				dispatchEvent( new  LogInEvent( LogInEvent.ACCESS_DENIED ) );
			}
			
			if ( !m_dropboxAPI.hasEventListener( DropboxEvent.METADATA_FAULT ) )
			{
				m_dropboxAPI.addEventListener( DropboxEvent.METADATA_FAULT, faultHandler );
			}
			
			m_dropboxAPI.metadata( _folderName, 1000, "", true );
		}
		
		
		//---------------------------------------------
		// Private methods
		//---------------------------------------------
		private function ensureApiWrapper() : void
		{
			if ( null == m_dropboxAPI )
			{
				m_dropboxAPI = new DropboxClient( m_config );
			}
		}
		
		
		private function signalLoginComplete( _accessKey : String = null, _accessSecret : String = null ) : void
		{			
			if ( !isEmpty( _accessKey ) && !isEmpty( _accessSecret ) )
			{
				// Here we can optionally add the _accessKey and _accessSecret details to the event
				// and let the application store them, so that the user doesn't have to log in again next time.
				
				dispatchEvent( new LogInEvent( LogInEvent.LOGIN_SUCCESS ) );
			}
			else
			{
				dispatchEvent( new LogInEvent( LogInEvent.LOGIN_FAILURE ) );
			}
		}
		
		
		private function handleDropboxLinkCancelled( _event : NativeDropboxLinkEvent ) : void
		{
			dispatchEvent( new LogInEvent( LogInEvent.CANCEL_LOGIN ) );	
		}
		
		
		private function handleDropboxLinked( _event : NativeDropboxLinkEvent ) : void
		{
			if ( null != _event.token && null != _event.tokenSecret )
			{
				m_dropboxAPI.config.accessTokenKey = _event.token;
				m_dropboxAPI.config.accessTokenSecret = _event.tokenSecret;
				
				signalLoginComplete( _event.token, _event.tokenSecret );
			}
			else
			{
				getRequestToken();
			}
		}
		
		
		private function handleDropboxUnlinked( _event : NativeDropboxLinkEvent ) : void
		{
			if ( null != m_dropboxAPI )
			{		
				m_dropboxAPI.config.accessTokenKey = "";
				m_dropboxAPI.config.accessTokenSecret = "";
				
				m_dropboxAPI = null;
			}
			
			dispatchEvent( new LogInEvent( LogInEvent.LOG_OUT ) );
		}
		
		
		private function getRequestToken() : void
		{				
			var encryptedSecret : String = SHA1.hash( m_config.consumerSecret );
			var sPart : String = encryptedSecret.substring( encryptedSecret.length - 8 );
			
			var url : String = "https://www.dropbox.com/" + m_config.apiVersion + "/connect?k=" + m_config.consumerKey + "&s=" + sPart;
			var urlRequest : URLRequest = new URLRequest( url );
			
			navigateToURL( urlRequest );
		}
		
		
		private static function isEmpty( _str : String ) : Boolean
		{			
			if ( null == _str )
			{
				return true;
			}
			
			if ( 0 == _str.length )
			{
				return true;
			}
			
			if ( "null" == _str )
			{
				return true;
			}
			
			return false;
		}
		
		
		//---------------------------------------------
		// Private members
		//---------------------------------------------
		private var m_config : DropboxConfig;
		private var m_dropboxAPI : DropboxClient;
		private var m_loginExt : NativeDropboxLogin;
		private var m_dropboxAccessType : String;
	}
}